package com.zh.common.ktx

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.app.ComponentActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.viewbinding.ViewBinding
import java.lang.reflect.ParameterizedType

class ViewBindingktx {
}

inline fun <reified VM : ViewModel> FragmentActivity.bindVM(): VM {
    return ViewModelProvider(this)[VM::class.java]
}

inline fun <reified VM : ViewModel> Fragment.bindVM(): VM {
    return ViewModelProvider(this)[VM::class.java]
}

fun <VB : ViewBinding> ComponentActivity.viewBinding(): VB {
    return bindViewBinding(javaClass, layoutInflater)
}

fun <VB : ViewBinding> Fragment.viewBinding(): VB {
    return bindViewBinding(javaClass, layoutInflater)
}

inline fun <reified VB : ViewBinding> View.viewBinding(): VB {
    return VB::class.java.getDeclaredMethod("bind", View::class.java)
        .invoke(null, this) as VB
}

inline fun <reified VB : ViewBinding> ViewGroup.viewBinding(): VB {
    return bindViewBinding(LayoutInflater.from(this.context), this, false)
}

/**
 * fragment直接引用有bug
 */
fun <VB : ViewBinding> Fragment.viewBinding(inflater: LayoutInflater, container: ViewGroup?): VB {
    return bindViewBinding(javaClass, inflater, container)
}

private fun <VB : ViewBinding> bindViewBinding(
    javaClass: Class<*>, layoutInflater: LayoutInflater
): VB {
    //利用反射 根据泛型得到 ViewBinding
    val superClass = javaClass.genericSuperclass
    val aClass = (superClass as ParameterizedType).actualTypeArguments[0] as Class<*>
    val method = aClass.getDeclaredMethod("inflate", LayoutInflater::class.java)
    return method.invoke(null, layoutInflater) as VB
}

private fun <VB : ViewBinding> bindViewBinding(
    javaClass: Class<*>, layoutInflater: LayoutInflater, container: ViewGroup?
): VB {
    //利用反射 根据泛型得到 ViewDataBinding
    val superClass = javaClass.genericSuperclass
    val aClass = (superClass as ParameterizedType).actualTypeArguments[0] as Class<*>
    val method = aClass.getDeclaredMethod(
        "inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java
    )
    return method.invoke(null, layoutInflater, container, false) as VB
}

inline fun <reified VB : ViewBinding> bindViewBinding(
    layoutInflater: LayoutInflater, parent: ViewGroup?, attachToParent: Boolean
): VB {
    return VB::class.java.getDeclaredMethod(
        "inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java
    ).invoke(null, layoutInflater, parent, attachToParent) as VB
}
